//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<Style.h>
///	@path	~/src/gui/style/
///	@date	2008/10/17
///	@desc	.

#pragma once

#include "xeres.h"

#include <map>

#include "lib/math/rect.h"
#include "lib/math/pair.h"
#include "lib/math/color.h"
#include "lib/utilities/dict.h"
#include "lib/utilities/time.h"
#include "lib/utilities/make_type.h"

#include "object/IObject.h"
#include "object/IVar.h"

namespace xeres {

	// forward declaration
	class StyleFontFamily;
	class IBitmap;

	/*! 
		\class	StyleFont
		\brief	Encapsulates a font structure for style used fonts.
	*/
	class StyleFont : public IObject
	{
	protected:

		/// \ctor
		StyleFont( StyleFontFamily * family , const WString& name , int height , int weight , bool itatlic , bool antialias );

		/// \dtor
		virtual ~StyleFont( void );

		DECL_IOBJECT_CLASS( StyleFont , IObject );

	public:

		/// \name	Font Service
		//@{

		/// \brief	Query font exist.
		static bool QueryFont( const WString& name );

		/// \brief	Install font.
		static bool InstallFont( const WString& file );

		/// \brief	Install font from memory.
		static bool InstallFontFromMemory( const WString& file , void * data , size_t size );

		/// \brief	Create font.
		static Ref<StyleFont> CreateFont( const WString& name = _S("") ,
			int height = 12 , int weight = 400 , bool italic = false , bool antialias = false );

		/// \brief	Get font face name.
		const WString& GetName( void ) const;

		/// \brief	Get font handle for DC.
		HFONT hfont( void ) { return m_font; }

		/// \brief	Get font logic height.
		int GetLogicHeight( void ) const { return m_height; }

		/// \brief	Get font pixel height.
		int GetFontHeight( void ) const { return m_fontheight; }

		/// \brief	Get font weight.
		int GetWeight( void ) const { return m_weight; }

		/// \brief	Get italic.
		bool GetItalic( void ) const { return m_italic; }

		/// \brief	Get antialias.
		bool GetAntialias( void ) const { return m_antialias; }

		/// \brief	Get ascent.
		int GetAscent( void ) const { return m_ascent; }

		/// \brief	Get descent.
		int GetDescent( void ) const { return m_descent; }

		/// \brief	Get baseline.
		int GetBaseline( void ) const { return m_baseline; }

		/// \brief	Get internal leading.
		int GetInternalLeading( void ) const { return m_internalLeading; }

		/// \brief	Get external leading.
		int GetExternalLeading( void ) const { return m_externalLeading; }

		/*! 
			\struct	FontChar
			\brief	Character data of font.
		*/
		struct FontChar
		{
			// char width (for bitblt width)
			int			m_width;
			int			m_step;
			int			m_aWidth;
			int			m_cWidth;
			uchar		m_buffer[1];
		};

		/// \brief	Get character data.
		FontChar * GetCharacter( int c );

		/// \brief	Get kerning pairs
		int GetPairs( wchar_t c1 , wchar_t c2 );

		//@}

	private:

		/// \brief	Create character of font.
		FontChar * CreateCharacter( int c );

		/// \brief	Create font data.
		FontChar * CreateFontData( size_t chunk_size );

		friend class StyleFontFamily;

		//@ data

		// text family
		StyleFontFamily * m_family;

		// text style
		int			m_height;
		int			m_weight;

		bool		m_italic;
		bool		m_antialias;
		bool		m_spare[2];

		// text detail info
		int			m_fontheight;
		int			m_ascent;
		int			m_descent;
		int			m_maxCharWidth;
		int			m_baseline;
		int			m_internalLeading;
		int			m_externalLeading;

		int			m_space;

		// text resources
		HFONT		m_font;
		HFONT		m_oldFont;
		HDC			m_hdc;
		HBITMAP		m_sprite;
		HBITMAP		m_oldBitmap;

		// text data buffer
		int			m_spritePitch;
		byte *		m_buffer;

		// kern pairing
		std::map<uint,int>		m_kernPairs;

		// font data
		std::map<int,FontChar*> m_chars;

		// font data size
		size_t		m_fontDataSize;
	};

	/*! 
		\class	PlacementStyle
		\brief	Determines how to place a component.
	*/
	class PlacementStyle
	{
	public:

		enum ALIGNMENT
		{
			KEEP		= 0 ,
			// Horizontal.
			LEFT		= 1 ,
			MIDDLE		= 2 ,
			RIGHT		= 3 ,
			// Vertical.
			TOP			= 4 ,
			CENTER		= 5 ,
			BOTTOM		= 6,
			ALIGNMENT_last
		};

	public:

		/// \ctor
		PlacementStyle( void );

		/// \ctor
		PlacementStyle( const PlacementStyle& rhs );

		/// \brief	Get corresponding image coordinate.
		Pair<int> GetImageCoord( const Pair<int>& size , const Rect<int>& place );

		/// \brief	Get available styles.
		static const std::vector<WString>& GetStyles( void );

	public:

		// Placement alignment.
		ALIGNMENT			m_horizontal;
		ALIGNMENT			m_vertical;
		
		// Placement padding.
		int					m_padding;
		int					m_padding_left;
		int					m_padding_top;
		int					m_padding_right;
		int					m_padding_bottom;

		
		// Placement margin.
		int					m_margin;
		int					m_margin_left;
		int					m_margin_top;
		int					m_margin_right;
		int					m_margin_bottom;

	public:
		// getter & setter
		PlacementStyle::ALIGNMENT GetHorizontal() const { return m_horizontal; }
		void SetHorizontal(PlacementStyle::ALIGNMENT val) { m_horizontal = val; }
	};

	/*! 
		\class	TextStyle
		\brief	Determines how text present in a style specified text block.
	*/
	class TextStyle
	{
	public:

		enum LETTER
		{
			LETTER_NORMAL	= 0 ,
			CAPITALIZE		= 1 ,
			LOWERCASE		= 2 ,
			UPPERCASE		= 3 ,
			LETTER_last
		};

		enum DECORATION
		{
			DECORATION_NONE	= 0 ,
			UNDERLINE		= 1 ,
			OVERLINE		= 2 ,
			BOTHLINE		= 3 ,
			LINE_THROUGH	= 4 ,
			DECORATION_last
		};

	public:

		/// \ctor
		TextStyle( void );

		/// \ctor
		TextStyle( const TextStyle& rhs );

		/// \brief	Arrange text by given data. Not break on newline.
		int ArrangeText( const wchar_t * text , int len , int * arrangement , wchar_t prev , int * width );

		/// \brief	Arrange text in a limit width & return text inside width. Might break by end of line (MUST use \n, NEVER \r).
		int ArrangeText( const wchar_t * text , int len , int * arrangement , int width_limit ,
			wchar_t prev , int * width , int ident , bool break_endl );

		/// \brief	Get corresponding letter.
		int GetLetter( int c , int last ) const;

		/// \bruef	Determine if override rhs text needs rearrange.
		bool NeedRearrange( const TextStyle& rhs ) const;

	public:

		// @data

		// Font of text.
		Ref<StyleFont>		m_font;

		// Text color.
		ARGB				m_textColor;

		// Extended text color.
		ARGB				m_edgeColor;
		ARGB				m_shadowColor;

		// Text background. (might be transparent)
		ARGB				m_textBackColor;

		// Text decoration.
		DECORATION			m_decoration;

		// Text height.
		int					m_lineHeight;

		// Text indent.
		int					m_textIndent;

		// Text offset.
		Pair<int>			m_textOffset;

		// Text spacing.
		int					m_textLetterSpacing;
		int					m_textWordSpacing;

		// Text transform.
		LETTER				m_textTransform;
	};

	/*! 
		\struct	ImageStyle
		\brief
	*/
	struct ImageStyle
	{
	public:

		/// \ctor
		ImageStyle( void );

		/// \ctor
		ImageStyle( const ImageStyle& rhs );

	public:

		// @data

		// Image color tint.
		ARGB				m_tint;

		// Image color filter.
		ARGB				m_filter;

		// Image border color.
		ARGB				m_borderColor;
	};

	/*! 
		\class	IStyle
		\brief	Style interface.
	*/
	class IStyle : public IObject
	{
	public:

		/// \ctor
		IStyle( void );

		/// \dtor
		virtual ~IStyle( void );

		DECL_IOBJECT_INTERFACE( IStyle , IObject );

	public:

		/// \brief	Query style.
		virtual RefWeak<IVar> QueryStyle( const WString& name ) = 0;

		/// \brief	Set style.
		virtual bool SetStyle( const WString& name , const WString& value ) = 0;
	};

	/*! 
		\class	CTextStyle
		\brief
	*/
	class CTextStyle : public IStyle , public MAKE_TYPE( PlacementStyle, TextStyle )
	{
	public:

		/// \ctor
		CTextStyle( void );

		/// \ctor
		CTextStyle( const CTextStyle& rhs );

		/// \dtor
		virtual ~CTextStyle( void );

		DECL_IOBJECT_CLASS_DYNAMIC( CTextStyle , IStyle );

	public:

		/// \brief	Query style.
		virtual RefWeak<IVar> QueryStyle( const WString& name );

		/// \brief	Set style.
		virtual bool SetStyle( const WString& name , const WString& value );

	};

	/*! 
		\class	CImageStyle
		\brief
	*/
	class CImageStyle : public IStyle , public MAKE_TYPE( PlacementStyle, ImageStyle )
	{
	public:

		/// \ctor
		CImageStyle( void );

		/// \dtor
		virtual ~CImageStyle( void );

		DECL_IOBJECT_CLASS_DYNAMIC( CImageStyle , IStyle );

	public:

		/// \brief	Query style.
		virtual RefWeak<IVar> QueryStyle( const WString& name );

		/// \brief	Set style.
		virtual bool SetStyle( const WString& name , const WString& value );

	};

} // namespace xeres
